/**
 * 
 */
package vue.globalBar;

import java.awt.Dimension;
import java.awt.GridLayout;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import vue.IIGSATPart;
import vue.session.IGBlock;
import vue.session.IGCNFUse;
import vue.session.IGExecutionBlock;
import vue.session.IGPreprocessorBlock;
import vue.session.IGSolverBlock;
import controller.ISessionManager;


/**
 * It is "bar" that display the information relative to the solver/preprocessor being, or that have
 * been executed, in the session.
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class IGGlobalExecutionBar extends JPanel implements IIGSATPart {

	private static final long				serialVersionUID		= 1L;
	public static final String				BORDER_TITLE			= "Global Execution Bar";
	public static final String				BORDER_RUNNING			= "Currently running";
	public static final String				BORDER_DONE				= "Previous execution";
	public static final String				BORDER_STATUS			= "Current status";


	public static final String				DEFAULT_STATUS_MESSAGE	= "Undetermined";
	public static final String				SAT_STATUS_MESSAGE		= "satisfiable !!";
	public static final String				UNSAT_STATUS_MESSAGE	= "Unsatisfiable !!";

	public static final int					HEIGHT					= 600;
	public static final int					WIDTH					= 300;

	protected int							width					= WIDTH;
	protected int							height					= HEIGHT;
	protected Dimension						dim;


	protected JPanel						runningPanel;
	protected JPanel						donePanel;

	private ISessionManager					manager;

	private List<IGBarSolver>				solverDone				= new LinkedList<IGBarSolver>();
	private List<IGBarPreprocessor>			preprocDone				= new LinkedList<IGBarPreprocessor>();
	private List<IGBarExecution>			running					= new LinkedList<IGBarExecution>();

	private IGBlock							selected				= null;
	private IGGlobalBarItem					itemSelected			= null;
	private Map<IGBlock, IGGlobalBarItem>	secondSelected			= new HashMap<IGBlock, IGGlobalBarItem>();


	/**
	 * Create a {@link IGGlobalExecutionBar}.
	 * 
	 * @param manager
	 *            the {@link ISessionManager}.
	 */
	public IGGlobalExecutionBar(ISessionManager manager) {
		// setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		setLayout(new GridLayout(2, 1));
		dim = new Dimension(width, height);
		this.manager = manager;

		// setLayout(new GridBagLayout());

		/*
		 * statusLabel = new JLabel("", JLabel.CENTER);
		 * statusLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
		 * statusLabel.setAlignmentY(JLabel.CENTER_ALIGNMENT); setUndeterminedStatus();
		 * statusLabel.setBorder(BorderFactory.createTitledBorder(BORDER_STATUS));
		 * statusLabel.setMaximumSize(new Dimension(width, height)); statusLabel.setOpaque(true);
		 * 
		 * add(statusLabel);
		 */
		JScrollPane scroll;

		// runningPanel = new JPanel(new GridLayout(0, 1));
		runningPanel = new JPanel();
		runningPanel.setLayout(new BoxLayout(runningPanel, BoxLayout.Y_AXIS));
		scroll = new JScrollPane(runningPanel);
		scroll.setBorder(BorderFactory.createTitledBorder(BORDER_RUNNING));
		// scroll.setAlignmentX(JPanel.CENTER_ALIGNMENT);
		// scroll.setAlignmentY(JPanel.CENTER_ALIGNMENT);
		// scroll.setMaximumSize(dim);

		add(scroll);

		// donePanel = new JPanel(new GridLayout(0, 1));
		donePanel = new JPanel();
		donePanel.setLayout(new BoxLayout(donePanel, BoxLayout.Y_AXIS));
		scroll = new JScrollPane(donePanel);
		scroll.setBorder(BorderFactory.createTitledBorder(BORDER_DONE));
		// scroll.setAlignmentX(JPanel.CENTER_ALIGNMENT);
		// scroll.setAlignmentY(JPanel.CENTER_ALIGNMENT);
		// scroll.setMaximumSize(dim);

		add(scroll);

		setBorder(BorderFactory.createTitledBorder(BORDER_TITLE));

		setPreferredSize(dim);
		setSize(dim);
	}

	@Override
	public void addCNFUse(IGCNFUse cnfuse) {
		// rien a faire
	}

	@Override
	public void addExecution(IGCNFUse cnfuse, IGExecutionBlock exec) {
		IGBarExecution tmp = new IGBarExecution(exec, manager);
		tmp.startTimer();
		running.add(tmp);
		runningPanel.add(tmp);
		runningPanel.validate();
	}

	@Override
	public void addPreprocessor(IGCNFUse cnfuse, IGPreprocessorBlock preproc, IGCNFUse res) {
		IGBarPreprocessor tmp = new IGBarPreprocessor(preproc, manager);
		preprocDone.add(tmp);
		donePanel.add(tmp);
		donePanel.validate();
	}

	@Override
	public void addSolver(IGCNFUse cnfuse, IGSolverBlock solver) {
		IGBarSolver tmp = new IGBarSolver(solver, manager);
		solverDone.add(tmp);
		donePanel.add(tmp);
		donePanel.validate();
	}

	@Override
	public void hasBeenModified(IGBlock block) {
		for (IGBarExecution exec : running)
			if (exec.getExec() == block)
			{
				exec.refresh();
				return;
			}

		for (IGBarSolver exec : solverDone)
			if (exec.getSolver() == block)
			{
				exec.refresh();
				return;
			}

		for (IGBarPreprocessor exec : preprocDone)
			if (exec.getPreproc() == block)
			{
				exec.refresh();
				return;
			}
	}

	@Override
	public void hasBeenRemoved(IGBlock block) {
		if (selected == block)
		{
			selected = null;
			itemSelected = null;
			for (IGGlobalBarItem sec : secondSelected.values())
				sec.setSecondSelected(false);
			secondSelected.clear();
		}
		else
			if (secondSelected != null)
				secondSelected.remove(block);


		IGBarExecution ex = null;
		for (IGBarExecution exec : running)
			if (exec.getExec() == block)
			{
				ex = exec;
				break;
			}
		if (ex != null)
		{
			ex.stopTimer();
			running.remove(ex);
			runningPanel.remove(ex);

			validate();
			repaint();
			return;
		}

		IGBarSolver sol = null;
		for (IGBarSolver exec : solverDone)
			if (exec.getSolver() == block)
			{
				sol = exec;
				break;
			}
		if (sol != null)
		{
			solverDone.remove(sol);
			donePanel.remove(sol);
			validate();
			repaint();
			return;
		}

		IGBarPreprocessor pre = null;
		for (IGBarPreprocessor exec : preprocDone)
			if (exec.getPreproc() == block)
			{
				pre = exec;
				break;
			}
		if (pre != null)
		{
			preprocDone.remove(pre);
			donePanel.remove(pre);
			validate();
			repaint();
			return;
		}
	}

	@Override
	public void hasBeenSelected(IGBlock block) {
		if (selected == block || block == null)
			return;

		if (selected != null)
		{
			itemSelected.setSelected(false);
			selected = null;
			itemSelected = null;
		}

		for (IGGlobalBarItem sec : secondSelected.values())
			sec.setSecondSelected(false);
		secondSelected.clear();

		Set<IGBlock> seconds = block.getSeconds();

		for (IGBlock b : seconds)
			System.out.println(b);
		System.out.println("terminer");

		for (IGBarExecution exec : running)
		{// check execution
			if (exec.getExec() == block)
			{// doot selectionne
				exec.setSelected(true);
				selected = block;
				itemSelected = exec;

				if (secondSelected.size() != seconds.size())
					continue;
				else
					return;
			}

			if (seconds.contains(exec.getExec()))
			{// ajoute au seconde selection
				secondSelected.put(exec.getExec(), exec);
				exec.setSecondSelected(true);

				if (secondSelected.size() == seconds.size() && selected != null)
					return;
			}
		}

		for (IGBarSolver exec : solverDone)
		{
			if (exec.getSolver() == block)
			{// doot selectionne
				exec.setSelected(true);
				selected = block;
				itemSelected = exec;

				if (secondSelected.size() != seconds.size())
					continue;
				else
					return;
			}

			if (seconds.contains(exec.getSolver()))
			{// ajoute au seconde selection
				secondSelected.put(exec.getSolver(), exec);
				exec.setSecondSelected(true);

				if (secondSelected.size() == seconds.size() && selected != null)
					return;
			}
		}

		for (IGBarPreprocessor exec : preprocDone)
		{
			if (exec.getPreproc() == block)
			{// doot selectionne
				exec.setSelected(true);
				selected = block;
				itemSelected = exec;

				if (secondSelected.size() != seconds.size())
					continue;
				else
					return;
			}

			if (seconds.contains(exec.getPreproc()))
			{// ajoute au seconde selection
				secondSelected.put(exec.getPreproc(), exec);
				exec.setSecondSelected(true);

				if (selected != null && secondSelected.size() == seconds.size())
					return;
			}
		}
	}

	/*
	 * @Override public void setSatisfiableStatus() { statusLabel.setText(SAT_STATUS_MESSAGE);
	 * statusLabel.setBackground(Color.GREEN); }
	 * 
	 * @Override public void setUnatisfiableStatus() { statusLabel.setText(UNSAT_STATUS_MESSAGE);
	 * statusLabel.setBackground(Color.RED); }
	 * 
	 * @Override public void setUndeterminedStatus() { statusLabel.setText(DEFAULT_STATUS_MESSAGE);
	 * statusLabel.setBackground(Color.GRAY); }
	 */


}
